package com.xiaoge.demo.configs.log.req_log;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 描述：  打印请求和返回参数 要求所有的controller中都使用统一的前缀
 * 作者：  郭永振
 * 时间：  2018-9-12 10:32:21
 */
@Component
@WebFilter(urlPatterns = {"/*"})
public class LoggingFilter extends OncePerRequestFilter {

    protected static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
    private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("/doc.html", "/swagger-resources", "/v2/api-docs")));

    private static final String REQUEST_PREFIX = "req:";
    private static final String RESPONSE_PREFIX = "res:";
    private AtomicLong id = new AtomicLong(1);

    @Value("${spring.profiles.active}")
    private String env; // 当前激活的配置文件

    private String reqStr = "";
    private String resStr = "";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, final FilterChain filterChain) {
        try {
            if (logger.isDebugEnabled()) {
                long requestId = id.incrementAndGet();

                response = new ResponseWrapper(requestId, response);
            }

            filterChain.doFilter(request, response);
            // response.flushBuffer();
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            // 如果当前是开发环境 就不再进行log打印
            if (!"dev".equals(env)) {
                return;
            }

            String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");
            boolean allowedPath = ALLOWED_PATHS.contains(path);
            if (allowedPath) {
                return;
            }
            // 忽略swaggerUi
            if (path.contains("/webjars/")) {
                return;
            }
            if (logger.isDebugEnabled()) {
                try {
                    logRequest(request);
                    logResponse((ResponseWrapper) response);
                    // 打印输出信息
                    StringBuilder msg = new StringBuilder();
                    msg.append(reqStr)
                            .append("├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
                            .append(resStr);

                    // 使用debug打印日志 info级别会被记录在error的log中
                    logger.debug(msg.toString());
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }
        }

    }

    private void logRequest(final HttpServletRequest request) throws Exception {
        // 组装输入打印
        StringBuilder msg = new StringBuilder();
        msg.append("\n").append("┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────");
        msg.append("\n").append("│").append(REQUEST_PREFIX).append("\n");
        msg.append("│    uri:").append(request.getRequestURI()).append("\n");

        // 过滤掉静态数据请求
        if (!isMultipart(request) && !isBinaryContent(request)) {

            msg.append("│    params:{").append("\n");
            Map<String, String[]> map = request.getParameterMap();
            // 遍历map打印请求数据
            for (Map.Entry<String, String[]> entry : map.entrySet()) {
                String key = String.valueOf(entry.getKey());
                String value = String.valueOf(entry.getValue()[0]);
                String valueStr = URLDecoder.decode(value, "utf-8");
                msg.append("│       " + key + ":").append(valueStr).append("\n");
            }

            msg.append("│    }").append("\n");
        }

        reqStr = msg.toString();
    }

    private boolean isBinaryContent(final HttpServletRequest request) {
        if (request.getContentType() == null) {
            return false;
        }
        return request.getContentType().startsWith("image") || request.getContentType().startsWith("video") || request.getContentType().startsWith("audio");
    }

    private boolean isMultipart(final HttpServletRequest request) {
        return request.getContentType() != null && request.getContentType().startsWith("multipart/form-data");
    }

    private void logResponse(final ResponseWrapper response) throws Exception {
        StringBuilder msg = new StringBuilder();
        msg.append("\n").append("│").append(RESPONSE_PREFIX).append("\n");
        msg.append("│    ").append(new String(response.toByteArray(), response.getCharacterEncoding())).append("\n");
        msg.append("└────────────────────────────────────────────────────────────────────────────────────────────────────────────────").append("\n\n\n");

        resStr = msg.toString();
    }

}